package com.hzmg.akka.Aspect;

import akka.actor.AbstractActor;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.http.javadsl.Http;
import akka.http.javadsl.ServerBuilder;
import com.google.common.collect.Maps;
import com.hzmg.akka.utils.NetUtils;
import com.hzmg.akka.utils.SpringUtils;
import com.hzmg.common.exception.AkkaCloudException;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zbw
 * @since 2022/8/14
 */
@Order(0)
@Component
public class RemoteServiceCreater implements ApplicationContextAware {
    static final Logger logger = LoggerFactory.getLogger(RemoteServiceCreater.class);
    ActorSystem actorSystem;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.inject(applicationContext);
        logger.info("spring application has benn created.");
        onApplicationEvent(applicationContext);
    }

    public void onApplicationEvent(ApplicationContext context) {
        logger.info("------初始化remoteCall----");
        try {

            //初始化actorSystem，用来创建actor
            init();
            // 获取所有beanNames
            String[] beanNames = context.getBeanNamesForType(Object.class);
            for (String beanName : beanNames) {

                RemoteServiceClass remoteServiceClass = context.findAnnotationOnBean(beanName,
                        RemoteServiceClass.class);


                //判断该类是否含有RemoteServiceClass注解
                if (remoteServiceClass != null) {
                    Object newInstance = context.getBean(beanName);
                    newInstance.getClass().newInstance();
                    Method[] methods = context.getBean(beanName).getClass()
                            .getDeclaredMethods();
                    for (Method method : methods) {
                        //判断该方法是否有RemoteServiceCall注解
                        if (method.isAnnotationPresent(RemoteServiceCall.class)) {
                            RemoteServiceCall remoteServiceCall = method
                                    .getAnnotation(RemoteServiceCall.class);

                            actorSystem.actorOf(Props.create(Actor.class, () -> new Actor(method, newInstance)), remoteServiceCall.name());
                            // do something
                            logger.info("注解方法：" + method.getName());
                            logger.info("method所带注解名称：" + method.getDeclaredAnnotations()[0]);
                            //getParameterAnnotations二维数组含义，第一维指的是参数，第二维指的是该参数的注解。

                            List<? extends Class<? extends Annotation>> parameterAnnotation= Arrays
                                    .stream(method.getParameterAnnotations()[0])
                                    .map(Annotation::annotationType)
                                    .collect(Collectors.toList());
                            if (parameterAnnotation.contains(RequestBody.class)) {
                                /*String bodyAsString = ctx.getBodyAsString();
                                argValues[i] = Json.decodeValue(bodyAsString, paramType);*/
                                logger.info("该参数拥有RequestBody注解");
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new AkkaCloudException(e.toString());
        }
    }

    /**
     * 正式版将不需要
     */
    public void init() {
        //设置工作端口，序列化方式，日志级别
        //正式版将会改成使用该worker已创建的actorSystem
        Map<String, Object> overrideConfig = Maps.newHashMap();
        String localIP = NetUtils.getLocalHost();
        overrideConfig.put("akka.remote.artery.canonical.hostname", localIP);
        overrideConfig.put("akka.remote.artery.canonical.port", "10087");
        String actorSystemAddress = localIP + ":" + "10087";
        logger.info("[AkkaDemo] akka-remote server address: {}", actorSystemAddress);
        Config akkaBasicConfig = ConfigFactory.load("hzmg-server.akka.conf");
        Config akkaFinalConfig = ConfigFactory.parseMap(overrideConfig).withFallback(akkaBasicConfig);

        //创建Actor工厂
        actorSystem = ActorSystem.create("remote-call", akkaFinalConfig);
        logger.info("actorSystem has benn cread by 10087");
        //创建akka http服务器
        Http http=Http.get(actorSystem);
        ServerBuilder serverBuilder=http.newServerAt(NetUtils.getLocalHost(),10087);

    }

    @AllArgsConstructor
    class Actor extends AbstractActor {

        Method method;
        Object newInstance;

        @Override
        public Receive createReceive() {
            return receiveBuilder()
                    .matchAny(this::onReceive)
                    .build();
        }

        void onReceive(Object obj) {
            try {
                logger.info(obj.toString());
                Object returnObj = method.invoke(newInstance, obj);
                getSender().tell(returnObj, getSelf());
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }
    class createInterfaceActor extends AbstractActor{

        @Override
        public Receive createReceive() {
            return null;
        }
    }
}




